package com.example.springboot.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.simple.SimpleDataSource;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class CodeUtils {

    private static final String TABLE_NAME = "book";  // 需要生成代码的表名称

    public static void main(String[] args) throws Exception {
        generate();
    }

    /*==============================   下面的不用改动  ==============================*/
    private static final String AUTHOR = "";   // 作者
    private static final String PACKAGE_NAME = "com.example.springboot";
    private static final String PROJECT_PATH = System.getProperty("user.dir");
    public static final String JAVA_CODE_PATH = PROJECT_PATH + "/springboot/src/main/java/";

    public static final String CONTROLLER_CODE_PATH = JAVA_CODE_PATH + "/com/example/springboot/controller/";  // controller代码的路径
    public static final String SERVICE_CODE_PATH = JAVA_CODE_PATH + "/com/example/springboot/service/";  // service代码的路径
    public static final String SERVICE_CODE_PATH_IMPL = JAVA_CODE_PATH + "/com/example/springboot/service/impl/";  // service实现类代码的路径
    public static final String MAPPER_CODE_PATH = JAVA_CODE_PATH + "/com/example/springboot/mapper/";  // mapper代码的路径
    public static final String MAPPER_XML_PATH = PROJECT_PATH + "/springboot/src/main/resources/mapper/";
    public static final String ENTITY_CODE_PATH = JAVA_CODE_PATH + "/com/example/springboot/entity/";  // entity代码的路径
    public static final String RESOURCES_PATH = PROJECT_PATH + "/springboot/src/main/resources/";
    private static final String VUE_CODE_PATH = PROJECT_PATH + "/vue/src/views/manager/";  // vue代码的路径
    private static final String SPACE4 = "    ";
    private static final String SPACE6 = "      ";
    private static final String SPACE8 = "        ";
    private static final String SPACE10 = SPACE4 + SPACE6;
    private static final String SPACE12 = SPACE8 + SPACE4;
    private static final String SPACE14 = SPACE8 + SPACE6;

    /**
     * 生成SpringBoot文件
     */
    public static void generate() throws Exception {
        createEntity(TABLE_NAME);   // 生成实体类
        createMapper(TABLE_NAME);   // 生成mapper
        createService(TABLE_NAME);  // 生成service
        createServiceImpl(TABLE_NAME);   // 生成service实现类
        createController(TABLE_NAME); // 生成controler
        createVue(TABLE_NAME);  // 生成vue

    }

    public static void createController(String tableName) {
        String modelName = getModelName(tableName);
        Map<String, String> map = new HashMap<>();
        map.put("modelName", modelName);
        map.put("entityName", getEntityName(tableName));
        String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/controller.template"), map);
        FileUtil.writeString(format, CONTROLLER_CODE_PATH + modelName + "Controller.java", "UTF-8");
    }
    public static void createService(String tableName) {
        String modelName = getModelName(tableName);
        Map<String, String> map = new HashMap<>();
        map.put("modelName", modelName);
        String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/iservice.template"), map);
        FileUtil.writeString(format, SERVICE_CODE_PATH + "I" + modelName + "Service.java", "UTF-8");
    }

    public static void createServiceImpl(String tableName) {
        String modelName = getModelName(tableName);
        Map<String, String> map = new HashMap<>();
        map.put("modelName", modelName);
        String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/service.template"), map);
        FileUtil.writeString(format, SERVICE_CODE_PATH_IMPL + modelName + "ServiceImpl.java", "UTF-8");
    }

    public static void createMapper(String tableName) {
        String modelName = getModelName(tableName);
        Map<String, String> map = new HashMap<>();
        map.put("modelName", modelName);
        String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/mapper.template"), map);
        FileUtil.writeString(format, MAPPER_CODE_PATH + modelName + "Mapper.java", "UTF-8");
    }

    public static void createEntity(String tableName) {
        try {
            String modelName = getModelName(tableName);
            List<TableColumn> tableColumns = getTableColumns(tableName);
            StringBuilder builder = StrUtil.builder().append("public class ").append(modelName).append(" {\n").append("\n");
            for (TableColumn tableColumn : tableColumns) {
                if (tableColumn.getName().equals("id")) {
                    builder.append(SPACE4).append("@TableId(type=IdType.AUTO)\n");
                }
                //builder.append(SPACE4).append("@Alias(\"").append(tableColumn.getComment()).append("\")\n");
                builder.append(SPACE4).append("private ").append(convertType(tableColumn.getDataType())).append(" ")
                        .append(StrUtil.toCamelCase(tableColumn.getName())).append(";\n");
            }
            builder.append("\n");
            builder.append("}");
            Map<String, Object> map = new HashMap<>();
            map.put("body", builder.toString());
            map.put("entityName", getEntityName(tableName));
            map.put("tableName", tableName);
            String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/entity.template"), map);
            FileUtil.writeString(format, ENTITY_CODE_PATH + modelName + ".java", "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getModelName(String tableName) {
        return StrUtil.upperFirst(getEntityName(tableName));
    }

    private static String getEntityName(String tableName) {
        tableName = tableName.replace("sys_", "").replace("t_", "");
        return StrUtil.toCamelCase(tableName);
    }

    /**
     * 生成vue文件
     */
    public static void createVue(String tableName) throws Exception {
        tableName = tableName.replace("sys_", "").replace("t_", "");
        String lowerEntityName = StrUtil.toCamelCase(tableName);
        String upperEntityName = StrUtil.upperFirst(lowerEntityName);
        StringBuilder tableColumnBuilder = new StringBuilder();
        StringBuilder formItemBuilder = new StringBuilder();
        StringBuilder formDetailItemBuilder = new StringBuilder();
        List<TableColumn> tableColumns = getTableColumns(tableName);
        for (TableColumn tableColumn : tableColumns) {
            if (tableColumn.getName().equals("id")) {
                continue;
            }
            String camelCaseName = StrUtil.toCamelCase(tableColumn.getName());
            // 生成表格
            if (tableColumn.getName().endsWith("img") || tableColumn.getName().endsWith("cover")) {
                tableColumnBuilder.append(SPACE10).append("<el-table-column align=\"center\" label=\"图片\"><template v-slot=\"scope\"><el-image style=\"width: 100px; height: 100px\" :src=\"scope.row.").append(camelCaseName).append("\" :preview-src-list=\"[scope.row.img]\"></el-image></template></el-table-column>\n");
            } else if (tableColumn.getName().endsWith("file")) {
                tableColumnBuilder.append(SPACE10).append("<el-table-column align=\"center\" label=\"文件\"><template v-slot=\"scope\"><el-button type=\"primary\" @click=\"download(scope.row.").append(camelCaseName).append(")\">下载</el-button></template></el-table-column>\n");
            } else {
                tableColumnBuilder.append(SPACE10).append("<el-table-column align=\"center\" prop=\"").append(camelCaseName).append("\" label=\"").append(tableColumn.getComment()).append("\"></el-table-column>\n");
            }
            // 生成表单
            StringBuilder formBuilder = formItemBuilder.append(SPACE8).append("<el-form-item prop=\"").append(camelCaseName).append("\" label=\"").append(tableColumn.getComment()).append("\">\n");
            if (tableColumn.getName().contains("time")) {
                // 日期时间
                formBuilder.append(SPACE10).append("<el-date-picker style='width:100%' v-model=\"form.").append(camelCaseName).append("\" type=\"datetime\" value-format=\"yyyy-MM-dd HH:mm:ss\" placeholder=\"选择日期时间\"></el-date-picker>\n");
            } else if (tableColumn.getName().endsWith("date")) {
                // 日期
                formBuilder.append(SPACE10).append("<el-date-picker style='width:100%' v-model=\"form.").append(camelCaseName).append("\" type=\"date\" value-format=\"yyyy-MM-dd\" placeholder=\"选择日期\"></el-date-picker>\n");
            } else if (tableColumn.getName().endsWith("file")) {
                // 文件上传
                formBuilder.append(SPACE10).append("<el-upload :action=\"$baseUrl +'/file/upload'\" :headers=\"{ token: user.token }\" ref=\"file\" :on-success=\"handleFileUploadSuccess\">\n");
                formBuilder.append(SPACE10).append("  <el-button size=\"small\" type=\"primary\">点击上传</el-button>\n");
                formBuilder.append(SPACE10).append("</el-upload>\n");
            } else if (tableColumn.getName().endsWith("img") || tableColumn.getName().endsWith("cover")) {
                // 文件上传
                formBuilder.append(SPACE10).append("<el-upload :action=\"$baseUrl +'/file/upload'\" :headers=\"{ token: user.token }\" ref=\"img\" :on-success=\"handleImgUploadSuccess\">\n");
                formBuilder.append(SPACE10).append("  <el-button size=\"small\" type=\"primary\">点击上传</el-button>\n");
                formBuilder.append(SPACE10).append("</el-upload>\n");
            } else {
                formBuilder.append(SPACE10).append("<el-input v-model=\"form.").append(camelCaseName).append("\" autocomplete=\"off\"></el-input>\n");
            }
            formBuilder.append(SPACE8).append("</el-form-item>\n");

            // 生成详情
            StringBuilder formDetailBuilder = formDetailItemBuilder.append(SPACE10).append("<el-form-item prop=\"").append(camelCaseName).append("\" label=\"").append(tableColumn.getComment()).append("\">\n");
            formDetailBuilder.append(SPACE12).append("<div>{{form.").append(camelCaseName).append("}}</div>\n");
            formDetailBuilder.append(SPACE10).append("</el-form-item>\n");
        }
        Map<String, String> map = new HashMap<>();
        map.put("tableColumn", tableColumnBuilder.toString());
        map.put("formItem", formItemBuilder.toString());
        map.put("formDetailItem", formDetailItemBuilder.toString());
        map.put("upperEntityName", upperEntityName);
        map.put("lowerEntityName", lowerEntityName);
        String format = StrUtil.format(FileUtil.readUtf8String(RESOURCES_PATH + "/templates/vue.template"), map);
        FileUtil.writeString(format, VUE_CODE_PATH + upperEntityName + ".vue", "UTF-8");
        System.out.println(upperEntityName + ".vue生成成功！");
    }

    /**
     * 获取数据库表字段
     * @param tableName
     * @return
     * @throws SQLException
     */
    private static List<TableColumn> getTableColumns(String tableName) throws SQLException {
        DBProp dbProp = getDBProp();
        String url = dbProp.getUrl();
        DataSource ds = new SimpleDataSource(url, dbProp.getUsername(), dbProp.getPassword());
        String sql = "SELECT table_name,column_name,data_type, column_comment FROM information_schema.COLUMNS WHERE table_schema = ? and table_name = ?";
        String schema = url.substring(url.lastIndexOf("3306/") +  5, url.indexOf("?"));
        List<Entity> list = Db.use(ds).query(sql, schema, tableName);
        List<TableColumn> columns = CollUtil.newArrayList();
        for (Entity entity : list) {
            TableColumn tableColumn = new TableColumn();
            String columnName = entity.getStr("column_name");
            tableColumn.setName(columnName);
            String comment = entity.getStr("column_comment");
            tableColumn.setComment(comment);
            String dataType = entity.getStr("data_type");
            tableColumn.setDataType(dataType);
            columns.add(tableColumn);
        }
        return columns;
    }

    /**
     * 获取数据库信息
     *
     * @return
     */
    private static DBProp getDBProp() {
        ClassPathResource resource = new ClassPathResource("application.yml");
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(resource);
        Properties dbProp = yamlPropertiesFactoryBean.getObject();
        return DBProp.builder().url(dbProp.getProperty("spring.datasource.url"))
                .username(dbProp.getProperty("spring.datasource.username"))
                .password(dbProp.getProperty("spring.datasource.password")).build();
    }

    /**
     * 数据库字段类型转换成Java数据类型
     * @param dbType 数据库字段类型
     * @return java字段类型
     */
    private static String convertType(String dbType) {
        switch (dbType) {
            case "int":
                return "Integer";
            case "double":
                return "Double";
            case "long":
                return "Long";
            case "varchar":
            case "text":
            case "longtext":
                return "String";
            case "datetime":
                return "Date";
            case "decimal":
                return "BigDecimal";
            case "tinyint":
                return "Boolean";
        }
        throw new RuntimeException("数据库表包含了不支持的数据类型：" + dbType);
    }
}
